package com.example.king.glutils;

import android.opengl.GLES20;
import android.text.TextUtils;

import static android.opengl.GLES20.*;

public class GlesUtil {


    public static int linkProgram(String vertexShaderCode, String fragmentShaderCode) {
        if (TextUtils.isEmpty(vertexShaderCode)) {
            throwError("vertex shader is empty!");
        }
        if (TextUtils.isEmpty(fragmentShaderCode)) {
            throwError("fragment shader is empty!");
        }

        int vertexShaderObjId = compileShader(GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShaderObjId = compileShader(GL_FRAGMENT_SHADER, fragmentShaderCode);

        return linkProgram(vertexShaderObjId, fragmentShaderObjId);
    }

    private static int linkProgram(int vertexShaderObjId, int fragmentShaderObjId) {
        final int programObjId = glCreateProgram();//创建一个program对象
        catchError("create program");

        //设置shader到program
        glAttachShader(programObjId, vertexShaderObjId);
        glAttachShader(programObjId, fragmentShaderObjId);

        //链接program
        glLinkProgram(programObjId);

        int status = checkProgramStatus(programObjId, GLES20.GL_LINK_STATUS);
        if (GLES20.GL_FALSE == status) {
            glDeleteProgram(programObjId);
            glDeleteShader(vertexShaderObjId);
            glDeleteShader(fragmentShaderObjId);
            throwError("link program error!\nInfo:" + glGetProgramInfoLog(programObjId));
        }

        return programObjId;

    }

    /**
     * 验证program
     *
     * @param programObjId
     * @return 是否成功验证
     */
    public static boolean validateProgram(int programObjId) {
        glValidateProgram(programObjId);

        final int[] validateStatus = new int[1];
        glGetProgramiv(programObjId, GL_VALIDATE_STATUS, validateStatus, 0);
        return validateStatus[0] != 0;
    }

    private static int compileShader(int type, String shaderCode) {
        final int shaderObjId = glCreateShader(type);//创建一个Shader对象
        catchError("createShader type:"+type);

        GLES20.glShaderSource(shaderObjId, shaderCode);
        catchError("shader source");

        GLES20.glCompileShader(shaderObjId);
        catchError("compileShader ");

        int status = checkShaderStatus(shaderObjId, GLES20.GL_COMPILE_STATUS);
        if (GLES20.GL_FALSE == status) {
            glDeleteShader(shaderObjId);
            catchError("delete shader");

            return GLES20.GL_FALSE;
        }

        return shaderObjId;
    }


    private static int checkShaderStatus(int shader, int shaderStatus) {
        int[] status = {GLES20.GL_TRUE};
        GLES20.glGetShaderiv(shader, shaderStatus, status, 0);
        catchError("checkShaderStatus");

        if (GLES20.GL_TRUE == status[0]) {
            return GLES20.GL_TRUE;
        }

        catchError("checkShaderStatus1");
        return GLES20.GL_FALSE;
    }

    private static int checkProgramStatus(int program, int programStatus) {
        int[] status = {GLES20.GL_TRUE};
        GLES20.glGetProgramiv(program, programStatus, status, 0);
        catchError("checkProgramStatus");

        if (GLES20.GL_TRUE == status[0]) {
            return GLES20.GL_TRUE;
        }

        catchError("checkProgramStatus1");
        return GLES20.GL_FALSE;
    }


    public static void catchError(String line) {
        int a = GLES20.glGetError();
        if (GLES20.GL_NO_ERROR != a) {
            throw new RuntimeException("CatchError:"+line + " " +a);
        }
    }

    private static void throwError(String msg) {
        throw new RuntimeException(msg);
    }
}
